/* $Id picture.cc jjs $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/
#define DEBUG_ROUTINE "picture"

#include <map>
#include <vector>
#include <dirent.h>
#include "picture.h"
#include "moros.h"
#include "../general/util.h"
#include "../general/log.h"
#define MAX_CACHE 1000

/**
\todo Missiles
    add missiles to the pictures

\todo Cache
    cache of pictures
    one use move picture to front of the cache
    drop at the end of the cache for space

\todo Map
    layers of images on a small map (11*15)
    paint of the map
    repaint of portions of the map on changes
        keep list of changes -> list of repainted tiles (ordered back to front)
    movement of map due to character movement = push tiles from server

\todo Edges
    find edges on the map between terrain types

\todo Units
    seperate list of units with current animation and position
    paint units on the map

\todo Recolour
    recolour: green is 30 points lower than the next colour
    iron to leather: blue -> brown

\todo Dither terrain
    find correct chances on certain variants
    ordered list of items with on change = highest first
    lover change on usage
    random range 64 bit with (5*x + 7*y) % 32 = random
    subtract from change to check if the next one is taken

\todo Projectiles
    seperate projectile list with trajectory, including height
*/

using namespace std;


char *edges[]={"ne","n","nw","sw","s","se"};
char *castles[]={"e","ne","nw","w", "sw","se"};

class edge {
  public:
    int from;
    int till;
    edge(int f, int t) {
        from=f;
        till=t;
        if (from<0) {
            from+=6;
            till+=6;
        }
    }
};

class tile {
    int terrain;
    std::vector<int> pictures;
};

int epos(int n) {
    while(n<0) n+=6;
    return n;
}

int dirnr=0;
std::vector<std::string> dirs;
std::map<std::string, int> files;

void add_directory(std::string dir) {
    DIR *dr=opendir(dir.c_str());
    if (dr==NULL) return;
    bool image=false;
    struct dirent *d;
    while (true) {
        d=readdir(dr);
        if (d==NULL) break;
        if (d->d_type==4 && d->d_name[0]!='.') {
            add_directory(dir+"/"+d->d_name);
        }
        if (d->d_type==8) {
            files[d->d_name]=dirnr++;
            image=true;
        }
    }
    closedir(dr);
    if (image) dirs.push_back(dir);
}

int variant(pos p, int max) {
    srandom(400+p.x+p.y*1000);
    int res=random() / (RAND_MAX/max);
    if (res>=max) res=max-1;
    return res;
}

pos image(pos size) {
    if (size.x==70) {
        return pos(35,35); // certain creature animations
    }
    if (size.x==72) {
        return pos(36,36); // normal tile, burned village
    }
    if (size.x==126) {
        if (size.y==180) return pos(63, 90); // wall e/nw
        if (size.y==144) return pos(63, 72); // wall ne/se/w
        if (size.y==160) return pos(63, 80); // wall sw
        if (size.y==180) return pos(90, 154); // village
    }
    if (size.x==150) {
        if (size.y==300) return pos(90,144); // reed
    }
    if (size.x==180) {
        if (size.y==252) return pos(90,144); // mountain, alt village
    }
    return pos(0,0);
}

class terrain {
  public:
    int dir;
    vector<edge> edges;
    vector<edge> snowedges;
    vector<edge> edges_water;
    vector<edge> snowedges_water;
    int vars;
    int snowvars;
    int flowers;
    int plant;
    int oasis;
    int rocks;
    int concave;
    int convex;
    terrain() { vars=0; flowers=0; plant=0; rocks=0; oasis=0; concave=0; convex=0;}
};

std::vector<terrain> terrains;

char* terrain_names[]={
    "ocean", "coast", "ford", "lava", "ice", "cave", "grass", "savanna", "dirt", "swamp", "desert",
    "desert-hills", "hills", "desert-mountains", "mountains", "wall"
};

void add_terrains() {
    unsigned int p;
    for(p=0; p<sizeof(terrain_names)/sizeof(terrain_names[0]); p++) {
        string t=terrain_names[p];
        int v,s;
        if (files.count(t+".png")>0) {
            terrains[p].vars=1;
            terrains[p].dir=files[t+".png"];
        }
        if (files.count(t+"-snow.png")>0) {
            terrains[p].snowvars=1;
        }
        if (files.count(t+"-oasis.png")>0) {
           terrains[p].oasis=1;
        }
        if (files.count(t+"-plant.png")>0) {
            terrains[p].plant+=1;
        }
        for (v=1; v<9; v++) {
            if (files.count(t+tostr(v)+".png")>0) {
                terrains[p].vars+=1>>v;
                terrains[p].dir=files[t+tostr(v)+".png"];
            }
            if (files.count(t+"-snow"+tostr(v)+".png")>0) {
                terrains[p].snowvars+=1>>v;
            }
            if (files.count(t+"-flowers"+tostr(v)+".png")>0) {
                terrains[p].flowers+=1>>v;
            }
            if (files.count(t+"-plant"+tostr(v)+".png")>0) {
                terrains[p].plant+=1>>v;
            }
            if (files.count(t+"-rocks"+tostr(v)+".png")>0) {
                terrains[p].rocks+=1>>v;
            }
        }
        for (v=0; v<6; v++) {
            if (files.count(t+"-concave-"+castles[v]+".png")>0) terrains[p].concave+=1>>v;
            if (files.count(t+"-convex-"+castles[v]+".png")>0) terrains[p].convex+=1>>v;
            string spin="";
            for (s=0; s<5; s++) {
                spin=spin+"-"+edges[epos(v-s)];
                if (files.count(t+spin+".png")>0) {
                    terrains[p].edges.push_back(edge(v-s, v));
                }
                if (files.count(t+"-to-water"+spin+".png")>0) {
                    terrains[p].edges_water.push_back(edge(v-s, v));
                }
                if (files.count(t+"-snow"+spin+".png")>0) {
                    terrains[p].snowedges.push_back(edge(v-s, v));
                }
                if (files.count(t+"-snow-to-water"+spin+".png")>0) {
                    terrains[p].snowedges_water.push_back(edge(v-s, v));
                }
            }
        }
    }
}

std::string get_terrain(int terr, int type, bool snow, int from, int to) {
    /*
    int t;
    terrain tr=terrains[terr];
    string res=dirs[terrains[terr].dir]+terrain_names[terr];
    bool one=false;
    switch(type) {
        case tt_normal:
            for (t=0; t<9; t++)  {
                if (tr.vars & 1>>t >0) {
                    res+="|"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_flower:
            for (t=0; t<9; t++)  {
                if (tr.flowers & 1>>t >0) {
                    res+="|-flowers"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_plant:
            for (t=0; t<9; t++)  {
                if (tr.plant & 1>>t >0) {
                    res+="|-plant"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_rocks:
            for (t=0; t<9; t++)  {
                if (tr.rocks & 1>>t >0) {
                    res+="|-rocks"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_oasis:
            for (t=0; t<9; t++)  {
                if (tr.oasis & 1>>t >0) {
                    res+="|-oasis"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_edge:
            for (t=0; t<9; t++)  {
                if (tr.oasis & 1>>t >0) {
                    res+="|-oasis"+(t>0?tostr(t):"")+".png";
                    one=true;
                }
            } break;
        case tt_towater:
        case tt_convex:
        case tt_concave:
            break;
    }
    if (!one) return "";
    return res;
    */
    return "";
}

class addition {
  public:
    int dir;
    int variant;
    int snowvariant;
    int burnedvariant;
};

std::vector<addition> additions;

char* adds_names[]={
    "pine", "great-tree", "willow", "farm-veg-spring", "tropical", "mountain_peak",
    "mine-abandoned", "rock", "river", "road", "road-bridge", "reed", "tent", "flag", "mushrooms",
    "windmill", "well", "village", "elven", "dwarven", "desert-village", "cave-village",
    "tropical-village", "swamp-village", "signpost", "scarecrow", "temple"
};

void add_additions() {
    unsigned int p;
    for (p=0; p<sizeof(adds_names)/sizeof(adds_names[0]); p++) {
        string a=adds_names[p];
        if (files.count(a+".png")>0) {
            additions[p].variant=1;
            additions[p].dir=files[a+".png"];
        }
        if (files.count(a+"-snow.png")>0) additions[p].snowvariant=1;
        if (files.count(a+"-burned.png")>0) additions[p].snowvariant=1;
        int t;
        for (t=1; t<5; t++) {
            if (files.count(a+tostr(t)+".png")>0) {
                additions[p].variant+=1>>t;
                additions[p].dir=files[a+tostr(t)+".png"];
            }
            if (files.count(a+"-snow"+tostr(t)+".png")>0) additions[p].snowvariant+=1>>t;
            if (files.count(a+"-burned"+tostr(t)+".png")>0) additions[p].snowvariant+=1>>t;
        }
    }
}

class wall {
  public:
    int dir;
    int concave;
    int convex;
    int keep_inside;
    int keep_keep;
};

std::vector<wall> walls;

char* wall_names[]={
    "castle", "encampment", "dwarven-castle", "elven-castle", "ruin"
};

void add_walls() {
    unsigned int p;
    for (p=0; p<sizeof(wall_names)/sizeof(wall_names[0]); p++) {
        string w=wall_names[p];
        int t;
        for(t=0; t<6; t++) {
            if (files.count(w+"-concave-"+castles[t]+".png")>0) {
                walls[p].concave+=1>>t;
                walls[p].dir=files[w+"-concave-"+castles[t]+".png"];
            }
            if (files.count(w+"-convex-"+castles[t]+".png")>0) walls[p].convex+=1>>t;
            if (files.count(w+"-keep-inside-"+castles[t]+".png")>0) walls[p].concave+=1>>t;
            if (files.count(w+"-keep-keep-"+castles[t]+".png")>0) walls[p].convex+=1>>t;
        }
    }
}

class unit {
  public:
    int dir;
    bool male;
    bool female;
    int moving;
    int melee;
    int ranged;
    int defend;
    int die;
    int idle;
    int fmoving;
    int fmelee;
    int franged;
    int fdefend;
    int fdie;
    int fidle;
};

std::vector<unit> units;

char* unit_names[]={
    "peasant", "woodsman", "townsman", "ruffian", "bandit", "white-cleric", "white-mage", "mage",
    "arch-mage", "bowman", "halberdier", "heavy-infantry", "horseman", "ranger",
    "knight", "lancer", "longbowman", "paladin", "pikeman", "spearman", "swordsman",
    "galleon", "pirate", "transport", "wagon", "horse", "falcon", "friar", "hunter", "shepherd",
    "camel", "elephant"
};

void add_units() {
    unsigned int p;
    for (p=0; p<sizeof(unit_names)/sizeof(unit_names[0]); p++) {
        string a=unit_names[p];
        if (files.count(a+".png")>0) {
            units[p].male=true;
            units[p].dir=files[a+".png"];
        }
        if (files.count(a+"-moving.png")>0) units[p].moving=1;
        if (files.count(a+"-melee.png")>0) units[p].melee=1;
        if (files.count(a+"-ranged.png")>0) units[p].ranged=1;
        if (files.count(a+"-defend.png")>0) units[p].defend=1;
        if (files.count(a+"-die.png")>0) units[p].die=1;
        if (files.count(a+"-idle.png")>0) units[p].idle=1;
        int t;
        for (t=1; t<9; t++) {
            if (files.count(a+"-moving-"+tostr(t)+".png")>0) units[p].moving+=1>>t;
            if (files.count(a+"-melee-"+tostr(t)+".png")>0) units[p].melee+=1>>t;
            if (files.count(a+"-ranged-"+tostr(t)+".png")>0) units[p].ranged+=1>>t;
            if (files.count(a+"-defend-"+tostr(t)+".png")>0) units[p].defend+=1>>t;
            if (files.count(a+"-die-"+tostr(t)+".png")>0) units[p].die+=1>>t;
            if (files.count(a+"-idle-"+tostr(t)+".png")>0) units[p].idle+=1>>t;
        }
        a=a+"+female";
        if (files.count(a+".png")>0) {
            units[p].female=true;
            if (files.count(a+"-moving.png")>0) units[p].fmoving=1;
            if (files.count(a+"-melee.png")>0) units[p].fmelee=1;
            if (files.count(a+"-ranged.png")>0) units[p].franged=1;
            if (files.count(a+"-defend.png")>0) units[p].fdefend=1;
            if (files.count(a+"-die.png")>0) units[p].fdie=1;
            if (files.count(a+"-idle.png")>0) units[p].fidle=1;
            int t;
            for (t=1; t<9; t++) {
                if (files.count(a+"-moving-"+tostr(t)+".png")>0) units[p].fmoving+=1>>t;
                if (files.count(a+"-melee-"+tostr(t)+".png")>0) units[p].fmelee+=1>>t;
                if (files.count(a+"-ranged-"+tostr(t)+".png")>0) units[p].franged+=1>>t;
                if (files.count(a+"-defend-"+tostr(t)+".png")>0) units[p].fdefend+=1>>t;
                if (files.count(a+"-die-"+tostr(t)+".png")>0) units[p].fdie+=1>>t;
                if (files.count(a+"-idle-"+tostr(t)+".png")>0) units[p].fidle+=1>>t;
            }
        }
    }
}

void add_images() {
    add_terrains();
    add_additions();
    add_walls();
    add_units();
}

/**
    set a terrain type
*/
void set_terrain(int type, int x, int y) {}
void set_add(int type, int x, int y, int dir) {}
void set_castle(int type, int x, int y) {}
void move_map(int dx, int dy) {}

int set_unit(int type, int action, int x, int y, int d, int u) {
    return 0;
}

void paint() {
}


#define side 36
#define hside 18

class tpos {
  public:
    tpos(int nx=0, int ny=0) {
        x=nx;
        y=ny;
        d=0;
        m=0;
    }
    int x;
    int y;
    int d;
    int m;
};

tpos calc_tpos(pos p) {
    tpos res;
    int ty=p.y / side;
    int iy=p.y % side;
    int tx;
    int ix;
    if (ty % 2==0) {
        tx=((p.x-iy/2)/side)*2;
        ix=(p.x-iy/2)-tx*hside;
        if (ix>side-iy) tx++;
        ix=p.x-tx*hside;
    } else {
        tx=((p.x-hside+iy/2)/side)*2;
        ix=(p.x-hside+iy/2)-tx*hside;
        if (ix>iy) tx++;
        ix=p.x-tx*hside;
    }
    res.x=tx/3;
    int rx=tx-res.x*3;
    res.y=ty/2;
    int ry=ty-res.y*2;
    if (tx % 2==1) {
        res.y=(ty-1)/2;
        ry=ty-1-res.y*2;
    }
    if (rx==2) {
        res.d=(ry==0?0:5);
        res.m=(ry==0?ix+hside-iy/2:ix+iy/2);
    } else if (rx==1) {
        res.d=(ry==0?1:4);
        res.m=(ry==0?side-iy:iy);
    } else {
        res.d=(ry==0?2:3);
        res.m=(ry==0?side-ix+hside-iy/2:side-ix+iy/2);
    }
    return res;
}

pos calc_pos(tpos p) {
    pos res;
    if (p.x % 2==0) {
        res.x=side+p.x*(side+hside);
        res.y=side+p.y*side*2;
    } else {
        res.x=side+p.x*(side+hside);
        res.y=side*2+p.y*side*2;
    }
    switch (p.d) {
        case 0: res.x+=p.m*3/4; res.y-=p.m/2; break;
        case 1: res.y-=p.m; break;
        case 2: res.x-=p.m*3/4; res.y-=p.m/2; break;
        case 3: res.x-=p.m*3/4; res.y+=p.m/2; break;
        case 4: res.y+=p.m; break;
        case 5: res.x+=p.m*3/4; res.y+=p.m/2; break;
    }
    return res;
}
